package Reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author fangkun
 * @create 2022-04-24-13:51
 */
public class ReflectTest {

    public static void main(String[] args) throws Exception {

        //TODO: 1、获取Class对象的三种方式

        //1.Object ——> getClass();
        Student student = new Student();
        Class<? extends Student> aClass = student.getClass();
        System.out.println(aClass.getName());

        //2.任何数据类型（包括基本数据类型）都有一个“静态”的class属性
        Class<Student> bClass = Student.class;
        System.out.println(aClass == bClass);

        //3.通过Class类的静态方法：forName（String  className）(常用)
        try {
            Class<?> cClass = Class.forName("Reflection.Student");
            System.out.println(aClass == cClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        /*
        * 注意：在运行期间，一个类，只有一个Class对象产生。
        * 三种方式常用第三种，第一种对象都有了还要反射干什么。第二种需要导入类的包，依赖太强，不导包就抛编译错误。
        * 一般都第三种，一个字符串可以传入也可写在配置文件中等多种方法。
        * */

        //TODO: 2.通过反射获取构造方法并使用

        Class<?> clazz = Class.forName("Reflection.Student");
        System.out.println("----------公有构造----------");
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor c: constructors){
            System.out.println(c);
        }

        System.out.println("----------所有构造----------");
        Constructor<?>[] constructors2 = clazz.getDeclaredConstructors();
        for (Constructor c: constructors2){
            System.out.println(c);
        }

        System.out.println("******************获取私有构造方法，并调用*******************************");
        Constructor<?> constructor = clazz.getDeclaredConstructor(int.class);
        System.out.println(constructor);
        constructor.setAccessible(true);
        constructor.newInstance(18);

        //TODO: 3、获取成员变量并调用

        System.out.println("************获取所有公有的字段********************");
        Field[] fieldArray = clazz.getFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }

        System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
        fieldArray = clazz.getDeclaredFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }

        System.out.println("*************获取公有字段并调用***********************************");
        Field f = clazz.getField("name");
        System.out.println(f);
        //获取一个对象
        Object obj = clazz.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
        //为字段设置值
        f.set(obj, "刘德华");
        //验证
        Student stu = (Student)obj;
        System.out.println("验证姓名：" + stu.name);

        System.out.println("**************获取私有字段****并调用********************************");
        f = clazz.getDeclaredField("age");
        System.out.println(f);
        f.setAccessible(true);//暴力反射，解除私有限定
        f.set(obj, 88);
        System.out.println("验证年龄：" + stu);

        //TODO: 4、获取成员方法并调用

        System.out.println("***************获取所有的”公有“方法*******************");
        Method[] methodArray = clazz.getMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }

        System.out.println("***************获取所有的方法，包括私有的*******************");
        methodArray = clazz.getDeclaredMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }

        System.out.println("***************获取公有的show1()方法*******************");
        Method m = clazz.getMethod("sayName", String.class);
        System.out.println(m);
        //实例化一个Student对象
        Object name = clazz.getConstructor().newInstance();
        m.invoke(obj, "刘德华");

        System.out.println("***************获取私有的show4()方法******************");
        m = clazz.getDeclaredMethod("sayAge", int.class);
        System.out.println(m);
        m.setAccessible(true);//解除私有限定
        Object result = m.invoke(obj, 20);//需要两个参数，一个是要调用的对象（获取有反射），一个是实参
        System.out.println("返回值：" + result);

        //TODO: 反射main方法

        System.out.println("***************main()方法******************");
        //2、获取main方法
        Method methodMain = clazz.getMethod("main", String[].class);//第一个参数：方法名称，第二个参数：方法形参的类型，
        //3、调用main方法
        // methodMain.invoke(null, new String[]{"a","b","c"});
        //第一个参数，对象类型，因为方法是static静态的，所以为null可以，第二个参数是String数组，这里要注意在jdk1.4时是数组，jdk1.5之后是可变参数
        //这里拆的时候将  new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
        methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
        // methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二

    }
}
